﻿package com.jeremyaburns
{
	import flash.geom.Point;

	/**
	 * An extension of Adobe's flash.geom.Point which implements 2D vector arithmetic.
	 */
	public class Vector2D extends Point
	{
		static public const ORIGIN :Vector2D = new Vector2D( 0, 0 );
		
		private const COS45 :Number = Math.cos( Math.PI / 4 );
		private const SIN45 :Number = Math.sin( Math.PI / 4 );
		
		public function Vector2D( x:Number = 0 , y:Number = 0 ) 
		{
				super( x, y );
		}
		
		public function get lengthSquared() :Number 
		{
				return x*x + y*y;
		}

		public function setTo( x:Number, y:Number ) :void
		{
				this.x = x;
				this.y = y;
		}
		
		public function setPolar( magnitude:Number, angle:Number ) :void
		{
				this.x = magnitude * Math.cos( angle );
				this.y = magnitude * Math.sin( angle );
		}
		
		public function copyFrom( point:Point ) :void
		{
				this.x = point.x;
				this.y = point.y;
		}
		
		public function cloneVector() :Vector2D
		{
				return new Vector2D( this.x, this.y );
		}

		override public function toString() :String
		{
				return "(x=" + x + ", y=" + y + ")";
		}
		
		public function plus( operand:Point, result:Vector2D = null ) :Vector2D
		{
				if( result == null ) result = new Vector2D;
				result.x = this.x + operand.x;
				result.y = this.y + operand.y;
				return result;
		}
		
		public function plusEquals( operand:Point ) :Vector2D
		{
				this.x += operand.x;
				this.y += operand.y;
				return this;
		}
		
		public function minus( operand:Point, result:Vector2D = null ) :Vector2D
		{
				if( result == null ) result = new Vector2D;
				result.x = this.x - operand.x;
				result.y = this.y - operand.y;
				return result;
		}
		
		public function minusEquals( operand:Point ) :Vector2D
		{
				this.x -= operand.x;
				this.y -= operand.y;
				return this;
		}
		
		public function times( operand:Number, result:Vector2D = null ) :Vector2D
		{
				if( result == null ) result = new Vector2D;
				result.x = this.x * operand;
				result.y = this.y * operand;
				return result;
		}
		
		public function timesEquals( operand:Number ) :Vector2D
		{
				this.x *= operand;
				this.y *= operand;
				return this;
		}
		
		public function div( operand:Number, result:Vector2D = null ) :Vector2D
		{
				if( result == null ) result = new Vector2D;
				result.x = this.x / operand;
				result.y = this.y / operand;
				return result;
		}
		
		public function divEquals( operand:Number ) :Vector2D
		{
				this.x /= operand;
				this.y /= operand;
				return this;
		}
		
		public function dot( operand:Point ) :Number
		{
				return this.x * operand.x + this.y * operand.y ;
		}
		
		public function cross( operand:Point ) :Number
		{
				return this.x * operand.y - this.y * operand.x ;
		}
		
		public function crossZ( z:Number, result:Vector2D = null ) :Vector2D
		{
				if( result == null ) result = new Vector2D( z*y, -z*x );
				return result;
		}
		
		public function rotate( radians:Number ) :void
		{
				var cos:Number = Math.cos( radians );
				var sin:Number = Math.sin( radians );
				var ox:Number  = this.x;
				this.x = ox * cos - this.y * sin ;
				this.y = ox * sin + this.y * cos ;
		}
		
		public function rotate45() :void
		{
				var ox:Number  = this.x;
				this.x = ox * COS45 - this.y * SIN45 ;
				this.y = ox * SIN45 + this.y * COS45 ;
		}
		
		public function rotateBack45() :void
		{
				var ox:Number  = this.x;
				this.x =  ox * COS45 + this.y * SIN45 ;
				this.y = -ox * SIN45 + this.y * COS45 ;
		}
		
		public function rotate90() :void
		{
				var ox:Number = this.x;
				this.x = -this.y;
				this.y = ox;
		}
		
		public function rotateBack90() :void
		{
				var ox:Number = this.x;
				this.x = this.y;
				this.y = -ox;
		}
		
		public function rotate180() :void
		{
				this.x = -this.x;
				this.y = -this.y;
		}
		
		public function reflect( unitNormal:Point, normalScale:Number = 1, tangentScale:Number = 1 ) :void
		{
				var unitTangent :Vector2D = new Vector2D( -unitNormal.y, unitNormal.x );
			   
				var normComponent :Number = dot( unitNormal  );
				var tangComponent :Number = dot( unitTangent );
			   
				normComponent *= -normalScale;
				tangComponent *=  tangentScale;
			   
				copyFrom( unitNormal );
				timesEquals( normComponent );
				unitTangent.timesEquals( tangComponent );
				plusEquals( unitTangent );
		}
		
	}
}






















